package com.decheng.java8.stream;

import com.decheng.java8.entity.Employee;
import com.decheng.java8.entity.EmployeeData;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 孔德成
 * @slogan 致敬大师，致敬未来的你
 * @date 2021/9/5 3:07 下午
 * @desc 收集 API 测试
 */

public class StreamApiCollectorsTest {

    private static final List<Employee> employees = EmployeeData.getEmployees();

    /**
     * 1. 查询工资大于6000的员工，收集到一个list中
     * 方法名：toList
     * 返回类型：List<T>
     * 作用：把流中元素收集到List
     */
    @Test
    public void testToList() {
        List<Employee> collect = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
        collect.forEach(System.out::println);
    }

    /**
     * 2. 查询工资大于6000的员工，收集到一个set中
     * 方法名：toSet
     * 返回类型：Set<T>
     * 作用：把流中元素收集到Set
     */
    @Test
    public void testToSet() {
        Set<Employee> collect = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
        collect.forEach(System.out::println);
    }

    /**
     * 3. 查询工资大于6000的员工，收集到一个ArrayList中
     * 方法名：toCollection
     * 返回类型：Collection<T>
     * 作用：把流中元素收集到创建的集合
     */
    @Test
    public void testToCollection() {
        ArrayList<Employee> collect = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toCollection(ArrayList::new));
        collect.forEach(System.out::println);
    }

    /**
     * 4. 计算工资大于6000的员工的数量
     * 方法名：counting
     * 返回类型：Long
     * 作用：计算流中元素的个数
     */
    @Test
    public void testCounting() {
        Long collect = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.counting());
        System.out.println("collect = " + collect);
    }

    /**
     * 5. 计算所有员工的工资总和
     * 方法名：summingDouble
     * 返回类型：Double
     * 作用：对流中元素的数值属性求和
     */
    @Test
    public void testSummingInt() {
        Double collect = employees.stream().collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println("collect = " + collect);
    }

    /**
     * 6. 计算所有员工的平均年龄
     * 方法名：averagingInt
     * 返回类型：Double
     * 作用：计算流中元素 Integer 属性的平均值
     */
    @Test
    public void testAveragingInt() {
        Double collect = employees.stream().collect(Collectors.averagingInt(Employee::getAge));
        System.out.println("collect = " + collect);
    }

    /**
     * 7. 对员工的年龄作统计
     * 方法名：summarizingInt
     * 返回类型：IntSummaryStatistics
     * 作用：收集流中 Integer 属性的统计值。
     */
    @Test
    public void testSummarizingInt() {
        IntSummaryStatistics collect = employees.stream().collect(Collectors.summarizingInt(Employee::getAge));
        System.out.println("collect = " + collect);
        System.out.println("count = " + collect.getCount());
        System.out.println("sum = " + collect.getSum());
        System.out.println("min = " + collect.getMin());
        System.out.println("average = " + collect.getAverage());
        System.out.println("max = " + collect.getMax());
    }

    /**
     * 8. 将所有员工的姓名拼在一起
     * 方法名：joining
     * 返回类型：String
     * 作用：连接流中每个字符串
     */
    @Test
    public void testJoining() {
        String collect = employees.stream().map(Employee::getName).collect(Collectors.joining());
        System.out.println("collect = " + collect);
    }

    /**
     * 9. 返回年龄最高的员工
     * 方法名：maxBy
     * 返回类型：Optional<T>
     * 作用：根据比较器选择最大值
     */
    @Test
    public void testMaxBy() {
        Optional<Employee> collect = employees.stream().collect(Collectors.maxBy(Comparator.comparingInt(Employee::getAge)));
        System.out.println("collect = " + collect);
    }

    /**
     * 10. 返回年龄最小的员工
     * 方法名：minBy
     * 返回类型：Optional<T>
     * 作用：根据比较器选择最小值
     */
    @Test
    public void testMinBy() {
        Optional<Employee> collect = employees.stream().collect(Collectors.minBy(Comparator.comparingInt(Employee::getAge)));
        System.out.println("collect = " + collect);
    }

    /**
     * 11. 计算员工的工资总和
     * 方法名：reducing
     * 返回类型：归约产生的类型
     * 作用：从一个作为累加器的初始值开始， 利用BinaryOperator与流中元素逐 个结合，从而归约成单个值
     */
    @Test
    public void testReducing() {
        Double collect = employees.stream().collect(Collectors.reducing(0.0, Employee::getSalary, Double::sum));
        System.out.println("collect = " + collect);
    }

    /**
     * 12. 统计工资大于6000的员工数量
     * 方法名：collectingAndThen
     * 返回类型：转换函数返回的类型
     * 作用：包裹另一个收集器，对其结果转换函数
     */
    @Test
    public void testCollectingAndThen() {
        Integer collect = employees.stream().filter(employee -> employee.getSalary() > 6000)
                .collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
        System.out.println("collect = " + collect);
    }

    /**
     * 13. 根据年龄对员工进行分组
     * 方法名：groupingBy
     * 返回类型：Map<K, List<T>>
     * 作用：根据某属性值对流分组，属性为K 结果为V
     */
    @Test
    public void testGroupingBy() {
        Map<Integer, List<Employee>> collect = employees.stream()
                .collect(Collectors.groupingBy(Employee::getAge, Collectors.toList()));
        collect.forEach((k, v) -> {
            System.out.println(k);
            v.forEach(System.out::println);
        });
    }

    /**
     * 14. 根据员工的状态进行分区
     * 方法名：partitioningBy
     * 返回类型：Map<Boolean, List<T>>
     * 作用：根据true或false进行分区
     */
    @Test
    public void testPartitioningBy() {
        Map<Boolean, List<Employee>> collect = employees.stream().collect(Collectors.partitioningBy(Employee::isStatus));
        collect.forEach((k, v) -> {
            System.out.println("k = " + k);
            v.forEach(System.out::println);
        });
    }
}